package djinni

// -RRR | 2023-07-04 | Changes START | To generate common.c and common.h files for the ArkTS folder

import djinni.ast._
import djinni.generatorTools._

class ArktsCommonCandHGenerator(spec: Spec) extends Generator(spec) {

  val fileName = "common.c"
  createFile(spec.arktsOutFolder.get, fileName, { (w: writer.IndentWriter) =>

    w.wl("#include <js_native_api.h>")
    w.wl("#include \"common.h\"")
    w.wl
    w.wl("#include <stdio.h>")
    w.wl

    w.wl("void add_returned_status(napi_env env,\n" +
      "\tconst char* key,\n" +
      "\tnapi_value object,\n" +
      "\tchar* expected_message,\n" +
      "\tnapi_status expected_status,\n" +
      "\tnapi_status actual_status)").braced {
      w.wl("char napi_message_string[100] = \"\";")
      w.wl("napi_value prop_value;")
      w.wl
      w.wl("if (actual_status != expected_status)").braced {

        w.wl("snprintf(napi_message_string, sizeof(napi_message_string),\n" +
          "\t\t\"Invalid status [%d]\", actual_status);")

      }
      w.wl
      w.wl("NODE_API_CALL_RETURN_VOID(env,\n" +
        "\tnapi_create_string_utf8(\n" +
        "\t\tenv,\n" +
        "\t\t(actual_status == expected_status ?\n" +
        "\t\texpected_message :\n" +
        "\t\tnapi_message_string),\n" +
        "\tNAPI_AUTO_LENGTH,\n" +
        "\t&prop_value));")

      w.wl("NODE_API_CALL_RETURN_VOID(env,\n" +
        "\tnapi_set_named_property(env, object, key, prop_value));")

    }
    w.wl

    w.wl("void add_last_status(napi_env env, const char* key, napi_value return_value)").braced {
      w.wl("napi_value prop_value;")
      w.wl("const napi_extended_error_info* p_last_error;")
      w.wl("NODE_API_CALL_RETURN_VOID(env,\n" +
        "\tnapi_get_last_error_info(env, &p_last_error));")
      w.wl
      w.wl("NODE_API_CALL_RETURN_VOID(env,\n" +
        "\tnapi_create_string_utf8(env,\n" +
        "\t\t(p_last_error->error_message == NULL ?\n" +
        "\t\t\"napi_ok\" :\n" +
        "\t\tp_last_error->error_message),\n" +
        "\tNAPI_AUTO_LENGTH,\n" +
        "\t&prop_value));")
      w.wl("NODE_API_CALL_RETURN_VOID(env,\n" +
        "\t\tnapi_set_named_property(env, return_value, key, prop_value));")
    }
  })

  val fileName2 = "common.h"
  createFile(spec.arktsOutFolder.get, fileName2, { (w: writer.IndentWriter) =>

    w.wl("#include <js_native_api.h>")
    w.wl

    w.wl("// Empty value so that macros here are able to return NULL or void")
    w.wl("#define NODE_API_RETVAL_NOTHING // Intentionally blank #define")
    w.wl
    // -RRR | 2024-05-28 | Changes START | New requirement support
    w.wl("#define GET_AND_THROW_LAST_ERROR(env)\\")
    w.w("\tdo {\\\n")
    w.wl("\t\tconst napi_extended_error_info *error_info;\\")
    w.wl("\t\tnapi_get_last_error_info((env), &error_info);\\")
    w.wl("\t\tbool is_pending;\\")
    w.wl("\t\tconst char* err_message = error_info->error_message;\\")
    w.wl("\t\tnapi_is_exception_pending((env), &is_pending);\\")
    w.wl("\t\t/* If an exception is already pending, don't throw it */\\")
    w.wl("\t\tif (!is_pending)\\\n\t\t{\\")
    w.wl("\t\t\tconst char* error_message = err_message != NULL ?\\\n" +
      "\t\t\terr_message :\\\n" +
      "\t\t\t\"empty error message\";\\")
    w.wl("\t\t\tnapi_throw_error((env), NULL, error_message);\\")
    w.wl("\t\t}\\")
    w.wl("\t}\\")
    w.wl("\twhile (0)")
    w.wl

    w.wl("#define NODE_API_ASSERT_BASE(env, assertion, message, ret_val)\\")
    w.wl("\tdo {\\")
    w.wl("\t\tif (!(assertion))\\\n\t\t{\\")
    w.wl("\t\t\tnapi_throw_error(\\\n" +
      "\t\t\t(env),\\\n" +
      "\t\t\tNULL,\\\n" +
      "\t\t\t\"assertion (\" #assertion \") failed: \" message);\\")
    w.wl("\t\t\treturn ret_val;\\")
    w.wl("\t\t}\\")
    w.wl("\t}\\")
    w.wl("\twhile (0)\\")
    w.wl

    w.wl("// Returns NULL on failed assertions.")
    w.wl("// This is meant yo be used inside napi_callback methods.")
    w.wl("#define NODE_API_ASSERT(env, assertion, message)\\")
    w.wl("\tNODE_API_ASSERT_BASE(env, assertion, message, NULL)")
    w.wl

    w.wl("// Returns empty on failed assertion.")
    w.wl("// This is meant to be used inside functions with void return type.")
    w.wl("#define NODE_API_ASSERT_RETURN_VOID(env, assertion, message)\\")
    w.wl("\tNODE_API_ASSERT_BASE(env, assertion, message, NODE_API_RETVAL_NOTHING)")
    w.wl

    w.wl("#define NODE_API_CALL_BASE(env, the_call, ret_val)\\")
    w.w("\tdo {\\\n")
    w.wl("\t\tif ((the_call) != napi_ok)\\\n\t\t{\\")
    w.wl("\t\t\tGET_AND_THROW_LAST_ERROR((env));\\")
    w.wl("\t\t\treturn ret_val;\\")
    w.wl("\t\t}\\")
    w.wl("\t}\\")
    w.wl("\twhile (0)")
    w.wl

    w.wl("// Returns NULL if the_call doesn't return napi_ok")
    w.wl("#define NODE_API_CALL(env, the_call)\\")
    w.wl("\tNODE_API_CALL_BASE(env, the_call, NULL)")
    w.wl

    w.wl("// Returns empty if the_call doesn't return napi_ok")
    w.wl("#define NODE_API_CALL_RETURN_VOID(env, the_call)\\")
    w.wl("\tNODE_API_CALL_BASE(env, the_call, NODE_API_RETVAL_NOTHING)")
    w.wl

    w.wl("#define DECLARE_NODE_API_PROPERTY(name, func)\\")
    w.wl("\t{ (name), NULL, (func), NULL, NULL, NULL, napi_default, NULL }")
    w.wl

    w.wl("#define DECLARE_NODE_API_GETTER(name, func)\\")
    w.wl("\t{ (name), NULL, NULL, (func), NULL, NULL, napi_default, NULL }")
    w.wl

    w.wl("#define DECLARE_NODE_API_PROPERTY_VALUE(name, value)\\")
    w.wl("\t{ (name), NULL, NULL, NULL, NULL, (value), napi_default, NULL }")
    w.wl
    // -RRR | 2024-05-28 | Changes END | New requirement support
    w.wl("void add_returned_status(napi_env env,\n" +
      "\tconst char* key,\n" +
      "\tnapi_value object,\n" +
      "\tchar* expected_message,\n" +
      "\tnapi_status expected_status,\n" +
      "\tnapi_status actual_status);")
    w.wl

    w.wl("void add_last_status(napi_env env, const char* key, napi_value return_value);")

  }
  )

  override def generateEnum(origin: String, ident: Ident, doc: Doc, e: Enum): Unit = {

  }

  override def generateRecord(origin: String, ident: Ident, doc: Doc, params: Seq[TypeParam], r: Record): Unit = {

  }

  override def generateInterface(origin: String, ident: Ident, doc: Doc, typeParams: Seq[TypeParam], i: Interface): Unit = {

  }
}

// -RRR | 2023-07-04 | Changes START | To generate common.c and common.h files for the ArkTS folder